Skip to content

agentdb: protocol for per-agent session storage - #1686

Merged
theomonnom merged 25 commits into
mainfrom
theo/agent-session-protos
Aug 5, 2026
Merged

agentdb: protocol for per-agent session storage#1686
theomonnom merged 25 commits into
mainfrom
theo/agent-session-protos

Conversation

@theomonnom

@theomonnom theomonnom commented Jul 27, 2026

Copy link
Copy Markdown
Member

No description provided.

livekit_agent_session_store.proto is the management API (Twirp): create, get,
list and delete a session, plus Dump for a consistent download URL.

livekit_agent_session_db.proto is the data plane: a request/response frame pair
over one WebSocket per session, correlated by client-chosen request_id, with
exec, query, atomic batch, interactive transactions, and credit-paced row
batches so any result size streams with bounded memory at every hop.
SessionValue mirrors SQLite's five storage classes.

The other twirp files change only because protoc-gen-twirp numbers file
descriptors by position in the invocation, so inserting one service shifts the
ones after it.
@changeset-bot

changeset-bot Bot commented Jul 27, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 2ea22ee

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

github-actions Bot and others added 2 commits July 27, 2026 17:41
Regenerated, so the same lines leave the Go doc comments.
theomonnom and others added 8 commits July 28, 2026 13:19
Gates the agent session store: creating, reading, querying, exporting and
deleting a project's session databases, on both the management API and the
data-plane connection. Without it that service could only verify that a token
was signed by a key belonging to the project, not what it was allowed to do.
Query results were row-oriented: a SessionValue message per cell plus its oneof
wrapper, which cost two allocations per cell on the server, the same again as
the client unmarshalled, and left the garbage collector walking pointer-dense
batches. A SessionColumnBatch carries a type tag per value (SQLite types values
individually, not by column) plus one packed array per storage class, with text
and blob bytes concatenated and addressed by exclusive end offsets rather than
repeated string, which is what lets a decoder hand out subslices of one buffer.

Measured end to end in the service, an 8000-row scan went from 47,819
allocations to 63, and a scalar-heavy batch is 43% smaller on the wire so more
rows fit per credit.

ListSessions now returns SessionSummary rather than GetSessionResponse, which
drops tip from listings. tip advances on every commit, so a listing index cannot
carry it without putting a write on the commit path, which means listing has to
read every session's metadata row to fill it in. It is also stale on arrival,
since anything acting on it must re-read. Everything else listing returns is
immutable, so a summary can be served straight from an index. GetSession still
returns tip for a single session.

A separate message rather than leaving the field unset: 0 is a valid tip, for a
session with no commits, so an unset field would be genuinely ambiguous.
An agent session is already a running conversation in this package's vocabulary
(agent/livekit_agent_session.proto carries chat messages, function calls and
handoffs), so agent.sessionAdmin read as authority over those rather than over
the session store's databases, which is what it gates. The store's service is
AgentSessionStore, so the grant now matches it.
They carried rationale from the implementation that motivated them, including Go
allocation counts, which does not belong in a protocol every SDK reads. What is
left states the contract: that values are typed per value rather than per column,
how the text and blob offsets address a value, and that a summary has no tip.
Review feedback: SessionStore, SessionValue, SessionPing and
CreateSessionRequest are far too generic for the flat livekit package,
where they would squat on names any other service might want. Prefixing
them (CSValue and friends) is noise at every call site, so these move to
their own namespace instead, the way protobufs/agent already does:
package livekit.agentdb, go_package livekit/agentdb. Inside it the names
need no prefix at all, so SessionValue becomes Value, SessionPing becomes
Ping, and SessionStoreRequest/Response become ClientMessage/ServerMessage,
which says what they are in a bidirectional protocol.

The same review observed the protocol reads like a cloud database rather
than anything to do with sessions, which is the conclusion the lifetime
question reached from the other side: a database whose TTL is unset never
expires and is meant to hold an agent's memory for years, so calling it a
session was already wrong. The unit is now a database: CreateDatabase,
GetDatabase, ListDatabases, DeleteDatabase, database_id, and the service
is AgentDB.

AgentGrant.SessionStoreAdmin becomes DatabaseAdmin (json databaseAdmin).

The namespace needs its own protoc invocation, since protoc-gen-twirp
refuses to mix go_package values in one run.
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Théo Monnom seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

github-actions Bot and others added 3 commits August 4, 2026 20:16
Reverts the livekit.agentdb namespace. The review asked for encapsulation
or prefixes, and a package of our own was a heavier answer than the
feedback called for.

Nesting gives the same encapsulation without either cost: every message
lives inside a container message AgentDB, so Value, Ping, Statement and
ClientMessage need no prefix and still cannot collide with anything else
in the livekit package. DataStream in livekit_models.proto already does
this, so it is house style rather than a new idea. Generated Go names are
AgentDB_Value, AgentDB_ClientMessage and so on.

Two consequences worth knowing. A service and a message cannot share a
name in one proto package, so the service is AgentDBService, matching
RoomService and AgentDispatchService. And a message cannot span files, so
the management and wire protos merge into livekit_agentdb.proto.

The eight twirp files touched are two lines each: adding a proto to the
shared twirp batch renumbers twirpFileDescriptorN across the batch, so
they have to be regenerated together.
Théo Monnom and others added 4 commits August 5, 2026 14:22
Comments say only what the shape does not. ttl_seconds keeps its
semantics (unset never expires, and expires_at_unix is 0 then) stated
once rather than repeated on four messages, tip is defined once on the
container, and the column encoding keeps its explanation because nothing
about the field names implies it. The restatements are gone.

QueryLang loses QUERY_LANG_CYPHER: the graph language is not public, so
the protocol should not name it. The number is reserved so nothing reuses
it.
…otos

# Conflicts:
#	livekit/livekit_agent_simulation.twirp.go
The container held two audiences at once: the Twirp control surface and the
WebSocket frames, separated only by a comment. Nesting the frames under
Wire makes the split structural, so a type name says which plane it belongs
to, and it stays one file with one top-level message.
@theomonnom theomonnom changed the title Add agent session store protocols agentdb: protocol for per-agent SQLite databases Aug 5, 2026
@theomonnom theomonnom changed the title agentdb: protocol for per-agent SQLite databases agentdb: protocol for per-agent session storage Aug 5, 2026
Théo Monnom and others added 6 commits August 5, 2026 14:45
No other proto here suffixes a timestamp with _unix; created_at,
started_at, ended_at and token_expires_at are the shape, so
created_at_unix and expires_at_unix lose the suffix. The ping fields carry
milliseconds and the repo marks non-second units (timestamp_ms,
started_at_ns), so they say _ms rather than leaving a reader to assume
seconds.

Also drops a claim about listing that is not true: ListDatabases
point-reads each head today.
Nothing read it. The server checked it was well-formed JSON, stored it, and
echoed it back; no path parsed, indexed or filtered on it, so it bought a
column and a validation step and nothing else. A caller that needs labels
can get them back as a map, with the PII annotation the rest of the repo
uses, once something actually consumes them.

Field numbers are renumbered rather than reserved: no client has ever
spoken this protocol.
Four RPCs were <Verb>Database and one was a bare Dump; it is DumpDatabase
now.

Nested enums drop their redundant prefixes, since the container already
namespaces them: DataStream.OperationType is CREATE, not
OPERATION_TYPE_CREATE, so ValueType is NULL through BLOB and QueryLang is
SQL. Generated names are AgentDB_Wire_NULL and AgentDB_Wire_SQL.
GetResponse and Summary described the same thing with four duplicated
fields, and Summary's missing tip was justified by a listing that reads
each head anyway. They collapse into Database, which get and list both
report, the way Room is one message that create and list both return.

GetDatabase returns it directly rather than through a wrapper.
@theomonnom
theomonnom merged commit e1e3629 into main Aug 5, 2026
7 of 8 checks passed
@theomonnom
theomonnom deleted the theo/agent-session-protos branch August 5, 2026 23:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants